package com.shiguiwu.springboot3.interceptor;

import cn.hutool.cache.CacheUtil;
import cn.hutool.cache.impl.TimedCache;
import cn.hutool.core.util.StrUtil;
import com.shiguiwu.springboot3.filter.HandleSqlFilter;
import com.shiguiwu.springboot3.properties.MybatisProperties;
import com.shiguiwu.springboot3.util.MybatisUtil;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.statement.Statement;
import org.apache.ibatis.cache.CacheKey;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.DatabaseIdProvider;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.springframework.beans.factory.annotation.Autowired;

import javax.sql.DataSource;
import java.util.Set;


/**
 * @description: sql拦截器
 * @author: stone
 * @date: Created by 2023/7/18 22:42
 * @version: 1.0.0
 * @pakeage: com.shiguiwu.springboot3.interceptor
 */
@Intercepts({
        @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class}),
        @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),
        @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class})
})
@Slf4j
@Data
public class SqlAdapterInterceptor implements Interceptor {

    private DatabaseIdProvider databaseIdProvider;

    private DataSource dataSource;
    //时间是毫秒单位
    TimedCache<Object, Object> sqlCache;

    @Autowired
    private HandleSqlFilter sqlFilter;


    public SqlAdapterInterceptor(DatabaseIdProvider databaseIdProvider, DataSource dataSource, MybatisProperties properties) {
        this.databaseIdProvider = databaseIdProvider;
        this.dataSource = dataSource;
        this.sqlCache = CacheUtil.newTimedCache(1000L * properties.getTimeout());

    }


    @Override
    public Object intercept(Invocation invocation) throws Throwable {

        MappedStatement ms = (MappedStatement) invocation.getArgs()[0];

        //<select databaseId="dm" > 类似这种，已经做了兼容性处理
        if (StrUtil.isNotBlank(ms.getDatabaseId())) {
            return invocation.proceed();
        }
        Object parameterObject = invocation.getArgs()[1];
        BoundSql boundSql = ms.getBoundSql(parameterObject);

        String originalSql = boundSql.getSql();

        Set<String> cols = handleSql(originalSql);

        log.debug("源sql ===> {}", originalSql);
        // 处理 SQL 语句
        String processedSql = (String) sqlCache.get(originalSql, () -> MybatisUtil.processSql(originalSql, dataSource, databaseIdProvider.getDatabaseId(dataSource), cols));
        log.debug("转化之后的sql ==> {}", processedSql);

        // 将处理后的 SQL 语句设置回去
        MybatisUtil.resetSql2Invocation(invocation, processedSql);
        return invocation.proceed();
    }

    public Set<String> handleSql(String originalSql) throws JSQLParserException {
        // 解析SQL语句
        Statement statement = CCJSqlParserUtil.parse(originalSql);
        return sqlFilter.handle(statement);
    }

    //public void extractColumnNames(Statement statement, List<String> columnNames) {
    //    List<String> wheres = new ArrayList<>();
    //    // 在这里根据SQL语句的类型提取表字段名
    //    if (statement instanceof Select) {
    //    } else if (statement instanceof Delete deleteStatement) {
    //        handleWhere(deleteStatement.getWhere(), wheres);
    //    } else if (statement instanceof Insert) {
    //        Insert insert = (Insert) statement;
    //        List<Column> columns = insert.getColumns();
    //        for (Column column : columns) {
    //            String columnName = column.getColumnName();
    //            columnNames.add(columnName);
    //        }
    //
    //
    //    } else if (statement instanceof Update) {
    //        Update update = (Update) statement;
    //        List<Column> columns = update.getColumns();
    //        for (Column column : columns) {
    //            String columnName = column.getColumnName();
    //            columnNames.add(columnName);
    //        }
    //        handleWhere(update.getWhere(), wheres);
    //    } else {
    //        log.error("不存在的操作 ===> {}", statement.toString());
    //    }
    //
    //    log.warn("where条件 ==> {}", wheres);
    //
    //}
    //
    //void handleWhere(Expression where, List<String> columnNames) {
    //    if (where != null) {
    //        where.accept(new ExpressionVisitorAdapter() {
    //            @Override
    //            public void visit(Column column) {
    //                columnNames.add(column.getColumnName());
    //            }
    //        });
    //    }
    //}

}
